package jsonrpc

import (
	md5lib "crypto/md5"
	"encoding/hex"

	"fmt"
	"math/rand"
	"strings"
	"time"

	us "gitee.com/gouyabin/go_utils"
)

const (
	// Success 0 .
	Success = 0
	// ParseErr -32700 语法解析错误,服务端接收到无效的json。该错误发送于服务器尝试解析json文本
	ParseErr = -32700
	// InvalidRequest -32600 无效请求发送的json不是一个有效的请求对象。
	InvalidRequest = -32600
	// MethodNotFound -32601 找不到方法 该方法不存在或无效
	MethodNotFound = -32601
	// InvalidParamErr -32602 无效的参数 无效的方法参数。
	InvalidParamErr = -32602
	// InternalErr -32603 内部错误 JSON-RPC内部错误。
	InternalErr = -32603
	// ServerErr       = -32000 // ServerErr -32000 to -32099 Server error服务端错误, 预留用于自定义的服务器错误。
	//认证错误
	AuthCheckErr = -32000
)

const (
	// VERSIONCODE const version code of JSONRPC
	VERSIONCODE = "2.0"
	basestr     = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	lenReqID    = 8
)

var Log *us.Logs

func init() {
	Log = us.Log
}

// Error . of rpc protocol
type Error struct {
	ErrCode int
	ErrMsg  string
}

func (r *Error) Error() string {
	return fmt.Sprintf("Error(code: %d, errmsg: %s)", r.ErrCode, r.ErrMsg)
}

// Wrap an error into this
func (r *Error) Wrap(err error) error {
	r.ErrMsg = fmt.Sprintf("Errmsg=%s", err.Error())
	return r
}

var errcodeMap = map[int]*Error{
	ParseErr:        &Error{ParseErr, "ParseErr"},
	InvalidRequest:  &Error{InvalidRequest, "InvalidRequest"},
	MethodNotFound:  &Error{MethodNotFound, "MethodNotFound"},
	InvalidParamErr: &Error{InvalidParamErr, "InvalidParamErr"},
	InternalErr:     &Error{InternalErr, "InternalErr"},
}

// md5 ...
func md5(s string) string {
	m := md5lib.New()
	m.Write([]byte(s))
	return hex.EncodeToString(m.Sum(nil))
}

var l = len(basestr)

// randstring ...
func randstring(length int) string {
	bs := []byte(basestr)
	result := make([]byte, 0, length)
	r := rand.New(rand.NewSource(time.Now().UnixNano()))
	for i := 0; i < length; i++ {
		result = append(result, bs[r.Intn(l)])
	}
	return string(result)
}

// randid request id(string) to send with NewRequest
func randid() string {
	s := randstring(lenReqID)
	return md5(s)
}

func parseFromRPCMethod(reqMethod string) (serviceName, methodName string, err error) {
	if strings.Count(reqMethod, ".") != 1 {
		return "", "", fmt.Errorf("rpc: service/method request ill-formed: %s", reqMethod)
	}
	dot := strings.LastIndex(reqMethod, ".")
	if dot < 0 {
		return "", "", fmt.Errorf("rpc: service/method request ill-formed: %s", reqMethod)
	}

	serviceName = reqMethod[:dot]
	methodName = reqMethod[dot+1:]

	return serviceName, methodName, nil
}
